﻿using CacheAttribute.Attributes;
using CacheAttribute.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CacheAttribute.Filter
{
    /// <summary>
    /// 异步过滤器，调用缓存方法
    /// </summary>
    public class AsyncCacheAtttibuteCheckFilter : IAsyncActionFilter
    {
        //缓存工具
        private readonly ICacheable _cache;

        //缓存策略
        private readonly CacheOperation operation;

        //日志工具
        private readonly ILogger<AsyncCacheAtttibuteCheckFilter> logger;

        public AsyncCacheAtttibuteCheckFilter(ICacheable cache, CacheOperation operation, ILogger<AsyncCacheAtttibuteCheckFilter> logger)
        {
            _cache = cache;
            this.operation = operation;
            this.logger = logger;
        }


        /// <summary>
        /// 异步过滤方法，可以用Invoke来直接调用
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            #region 方法执行前
            logger.LogInformation("方法执行前，获取参数");

            //强转获取cntroller实例
            ControllerActionDescriptor controller = (ControllerActionDescriptor)context.ActionDescriptor;
            //获取调用接口的反射对象
            MethodInfo action = controller.MethodInfo;

            //获取Cacheable注解
            CacheAbleAttribute cacheable = (CacheAbleAttribute)action.GetCustomAttribute(typeof(CacheAbleAttribute));

            //获取CacheDel注解
            CacheDelAttribute cacheDel = (CacheDelAttribute)action.GetCustomAttribute(typeof(CacheDelAttribute));

            //获取CacheUpdate注解
            CacheUpdateAttribute cacheUpdate = (CacheUpdateAttribute)action.GetCustomAttribute(typeof(CacheUpdateAttribute));

            #region CacheAble注解处理
            //当有cacheable注解时
            if (cacheable != null)
            {
                //当使用CacheAble时,同时也具有CacheInit时，先处理CacheInit
                if (action.GetCustomAttribute(typeof(CacheInitAttribute)) != null)
                {
                    bool isSus = operation.CacheInit_strategy(context, _cache);
                }
                //执行方法前如果查到有缓存，就传回来作为result返回(短路调用)，没查到就返回Null
                object result = operation.CacheAble_Strategy_Before(context, _cache);
                if(result != null)
                {
                    
                    ObjectResult rs = new ObjectResult(result);
                    context.Result = rs;
                    return ;  
                    
                }
                    

            }
            #endregion

            //删除正则匹配到的缓存
            if (cacheDel != null)
            {
                if (!operation.CacheDel_strategy(context, _cache))
                {
                    logger.LogInformation(this.GetType().Name + ":" + "没有相应的缓存被删除");
                }
                else
                {
                    logger.LogInformation(this.GetType().Name + ":" + "删除了相应的缓存");
                }
            }

            //相当于强化版的Cacheable注解
            if (cacheUpdate != null && cacheUpdate.work == true)
            {
                object res = operation.CacheUpdate_strategy_Before(context, _cache);

                if(res != null)
                {
                    ObjectResult rs = new ObjectResult(res);
                    context.Result = rs;
                    return;
                }

            }

            #endregion 

            //await next();

            #region 方法执行后
            logger.LogInformation("方法执行后，去获取结果");

            Task<ActionExecutedContext> task = next.Invoke();
            
            ControllerActionDescriptor controller2 = (ControllerActionDescriptor)context.ActionDescriptor;

            MethodInfo action2 = controller.MethodInfo;

            //获取cacheable注解
            CacheAbleAttribute cacheable2 = (CacheAbleAttribute)action2.GetCustomAttribute(typeof(CacheAbleAttribute));

            //获取cacheUpdate注解
            CacheUpdateAttribute cacheUpdate2 = (CacheUpdateAttribute)action2.GetCustomAttribute(typeof(CacheUpdateAttribute));

            //当有cacheable注解时
            if (cacheable2 != null && cacheable2.work == true)
            {

                operation.CacheAble_Strategy_After(task.Result,context, _cache);

            }

            if (cacheUpdate2 != null && cacheUpdate2.work == true)
            {
                operation.CacheUpdate_strategy_After(task.Result,context, _cache);
            }
            #endregion

        }
    }
}

